package user

import (
	"errors"
	"cgs-server/helper"
	"cgs-server/server"
	"cgs-server/server/base"
	"cgs-server/server/model"
	"go.mongodb.org/mongo-driver/bson"
)

type UserRepository interface {
	base.Repository
	ChangePassword(mdl *model.DataUserModel) error
	FindByUsername(username string) (*model.User, error)

	// 根据TenantId查询应用列表
	FindByTenantId(collectionName, tenantId string) ([]*model.Visual, error)
	FindByDept(deptId string)(interface{},error)
}

func NewUserRepository() UserRepository {
	return &userRepository{base.RepositoryStruct{
		CollectionName: server.UserCollectionName,
	}}
}

type userRepository struct {
	base.RepositoryStruct
}

func (u *userRepository) FindByTenantId(collectionName, tenantId string) ([]*model.Visual, error) {
	if err := u.CheckDB(); err != nil {
		return nil, err
	}
	filter := bson.M{
		"$and": bson.A{
			bson.M{
				"$or": bson.A{
					bson.M{
						"tenantId": tenantId,
					},
					bson.M{
						"tenantId": nil,
					},
				},
			},
			bson.M{
				"$or": bson.A{
					bson.M{
						"isDeleted": 0,
					},
					bson.M{
						"isDeleted": nil,
					},
				},
			},
		},
	}
	results := []*model.Visual{}
	err := u.Mongo.FindMany(collectionName, filter, &results)
	if err != nil {
		return nil, err
	}
	return results, nil
}

func (u *userRepository) Insert(duModel *model.DataUserModel) error {
	if err := u.CheckDB(); err != nil {
		return err
	}
	user := duModel.Data.(*model.User)
	user.ResolveEntity(user, duModel.User)

	_, err := u.Mongo.InsertOne(u.CollectionName, user)
	return err
}

func (u *userRepository) ChangePassword(mdl *model.DataUserModel) error {
	if changeModel, ok := mdl.Data.(*model.ChangeUserPasswordModel); ok {
		if mdl.User == nil {
			return errors.New("The user is not existed.")
		}
		if err := u.CheckDB(); err != nil {
			return err
		}
		filter := bson.M{
			"ID": changeModel.UserId,
		}
		changeModel.ResolveFilter(changeModel, mdl.User, &filter)
		updateOpt := bson.M{
			"Password": changeModel.Password,
			"Salt": changeModel.Salt,
		}
		changeModel.ResolveUpdateCondition(changeModel, mdl.User, &updateOpt)
		update := bson.M{
			"$set": updateOpt,
		}

		_, err := u.Mongo.UpdateOne(u.CollectionName, filter, update)
		return err
	}
	return errors.New("model.DataUserModel.Data is not type of model.ChangeUserPasswordModel")
}

// 更新用户
func (u *userRepository) Update(duModel *model.DataUserModel) error {
	if err := u.CheckDB(); err != nil {
		return err
	}
	user := duModel.Data.(*model.User)
	filter := bson.M{
		"ID": user.UserId,
	}
	user.ResolveFilter(user, duModel.User, &filter)

	updateOpt := bson.M{}
	// 用户名 Username 不允许修改，密码在ChangPassword()修改
	if user.Name != "" {
		updateOpt["Name"] = user.Name
	}
	//if user.Depts != nil{
		updateOpt["Depts"]=user.Depts
	//}
	if user.DeptID != "" {
		updateOpt["DeptId"] = user.DeptID
	}
	if user.Gender != 0 {
		updateOpt["Gender"] = user.Gender
	}
	if helper.CheckPhone(user.Phone) {
		updateOpt["Phone"] = user.Phone
	}
	if helper.CheckEmail(user.Email) {
		updateOpt["Email"] = user.Email
	}
	if helper.CheckQQ(user.QQ) {
		updateOpt["QQ"] = user.QQ
	}
	if user.RoleID != "" {
		updateOpt["RoleID"] = user.RoleID
	}

	user.ResolveUpdateCondition(user, duModel.User, &updateOpt)
	update := bson.M{
		"$set": updateOpt,
	}

	_, err := u.Mongo.UpdateOne(u.CollectionName, filter, update)
	return err
}

// 根据id，获取用户，可能需要一个 GetById() 方法
func (u *userRepository) FindOne(duModel *model.DataUserModel) (interface{}, error) {
	if err := u.CheckDB(); err != nil {
		return nil, err
	}
	user := duModel.Data.(*model.User)
	filter := bson.M{
		"ID": user.UserId,
	}
	if duModel.Filter != nil {
		filter = *duModel.Filter
	}
	user.ResolveFilter(user, duModel.User, &filter)
	result := model.User{}
	find, _ := u.Mongo.FindOne(u.CollectionName, filter, &result)
	if !find {
		return nil, errors.New("The user is not existed.")
	}
	return &result, nil
}

func (u *userRepository) FindByUsername(username string) (*model.User, error) {
	if err := u.CheckDB(); err != nil {
		return nil, err
	}
	if username == "" {
		return nil, errors.New("Username can not be empty")
	}

	filter := bson.M{
		"Username": username,
		"$or": bson.A{
			bson.M{
				"isDeleted": 0,
			},
			bson.M{
				"isDeleted": nil,
			},
		},
	}
	result := &model.User{}
	find, err := u.Mongo.FindOne(u.CollectionName, filter, result)
	if err != nil {
		return nil, err
	}
	if find {
		return result, nil
	}
	return nil, nil
}
func (u *userRepository) FindByDept(deptId string) (interface{}, error) {
	if err := u.CheckDB(); err != nil {
		return nil, err
	}
	if deptId == "" {
		return nil, errors.New("Username can not be empty")
	}
	filter := bson.M{
		"Depts": bson.M{
			"$regex":deptId,
			"$options": "$i",
		},
		"$or": bson.A{
			bson.M{
				"isDeleted": 0,
			},
			bson.M{
				"isDeleted": nil,
			},
		},
	}
	results := model.Users{}
	err := u.Mongo.FindMany(u.CollectionName, filter, &results)
	if err != nil {
		return nil, err
	}
	return results, nil
}
func (u *userRepository) Find(mdl *model.DataUserModel) (interface{}, error) {
	if user, ok := mdl.Data.(*model.User); ok {
		if err := u.CheckDB(); err != nil {
			return nil, err
		}
		results := model.Users{} // 数据库RoleID string -> struct#ObjectID 转换有问题
		//results := bson.A{}
		filter := bson.M{}
		user.ResolveFilter(user, mdl.User, &filter)
		err := u.Mongo.FindMany(u.CollectionName, filter, &results)
		if err != nil {
			return nil, err
		}
		return results, nil
	}

	return nil, errors.New("Type error.")
}

func (u *userRepository) DeleteLogic(mdl *model.DataUserModel) error {
	if user, ok := mdl.Data.(*model.User); ok {
		if err := u.CheckDB(); err != nil {
			return err
		}
		filter := bson.M{
			"ID": user.UserId,
		}
		user.ResolveFilter(user, mdl.User, &filter)
		updateOpt := bson.M{}
		user.DeleteLogic(user, mdl.User, &updateOpt)
		update := bson.M{
			"$set": updateOpt,
		}
		_, err := u.Mongo.UpdateOne(u.CollectionName, filter, update)
		return err
	} else {
		return errors.New("User type error.")
	}
}

func (u *userRepository) Count(mdl *model.DataUserModel) (int64, error) {
	if err := u.CheckDB(); err != nil {
		return 0, err
	}
	filter := bson.M{}
	if mdl.Filter != nil {
		filter = *mdl.Filter
	}
	return u.Mongo.Count(u.CollectionName, filter)
}

func (u *userRepository) BatchDeleteLogic(mdl *model.DataUserModel) error {
	if user, ok := mdl.Data.(*model.User); ok {
		if err := u.CheckDB(); err != nil {
			return err
		}
		if mdl.Filter == nil {
			return errors.New("filter is required")
		}
		filter := *mdl.Filter
		updateOpt := bson.M{}
		user.DeleteLogic(user, mdl.User, &updateOpt)
		update := bson.M{
			"$set": updateOpt,
		}
		_, err := u.Mongo.UpdateMany(u.CollectionName, filter, update)
		return err
	} else {
		return model.NewTypeError("user")
	}
}
